package ph.com.gs3.formalistics.notification.receiver.services;

import ph.com.gs3.formalistics.notification.receiver.managers.RealTimeEventsManager;
import ph.com.gs3.formalistics.notification.receiver.managers.RealTimeEventsManager.RealTimeEventsManagerListener;
import ph.com.gs3.formalistics.notification.receiver.model.valueobjects.business.User;
import ph.com.gs3.formalistics.notification.receiver.model.valueobjects.business.UserStub;
import ph.com.gs3.formalistics.notification.receiver.utilities.FLLogger;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;

public class NotifierService extends Service implements RealTimeEventsManagerListener {

	// ===============================================================================
	// {{ Constants
	public static final String TAG = NotifierService.class.getSimpleName();
	public static final String NAME = NotifierService.class.getName();

	// broadcasted actions
	public static final String ACTION_ON_CONNECTED = NAME + "_on_connected";
	public static final String ACTION_ON_DISCONNECTED = NAME + "_on_disconnected";
	public static final String ACTION_ON_USER_LOGGED_IN = NAME + "_on_user_logged_in";
	public static final String ACTION_ON_USER_LOGGED_OUT = NAME + "_on_user_logged_out";
	public static final String ACTION_ON_NOTIFICATION_RECEIVED = NAME + "_on_notification_received";
	public static final String ACTION_ON_MESSAGE_RECEIVED = NAME + "_on_message_received";

	// incoming extras
	public static final String EXTRA_PORT = "port";
	public static final String EXTRA_CURRENT_USER = "current_user";

	// outgoing extras
	public static final String EXTRA_LOGGED_IN_USER = "logged_in_user";
	public static final String EXTRA_LOGGED_OUT_USER = "logged_out_user_id";
	public static final String EXTRA_RECIEVED_MESSAGE = "recieved_message";

	// }}

	private static boolean serviceRunning = false;

	private int socketServerPort;
	private User currentUser;

	// ===============================================================================
	// {{ Service Life Cycle Implementation Methods

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {

		Bundle extras = intent.getExtras();

		if (!serviceRunning) {
			// start the service
			startService(extras);

			FLLogger.d(TAG, "Started");
		} else {

			// restart the service
			stopService();
			startService(extras);

			FLLogger.d(TAG, "Restarted");
		}

		return START_REDELIVER_INTENT;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		stopService();
		FLLogger.d(TAG, "Service destroyed");
	}

	@Override
	public void onLowMemory() {
		super.onLowMemory();

		FLLogger.w(TAG, "Running out of memory");
	}

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	// }}

	// ===============================================================================
	// {{ Functional Methods

	private void startService(Bundle extras) {
		initializeAndValidateParametersToTemp(extras);
		RealTimeEventsManager.getDefaultInstance().connect(currentUser, socketServerPort);
		RealTimeEventsManager.getDefaultInstance().registerListner(this);
		serviceRunning = true;
	}

	private void stopService() {

		RealTimeEventsManager.getDefaultInstance().unregisterListener(this);
		RealTimeEventsManager.getDefaultInstance().disconnect();
		serviceRunning = false;

	}

	private void initializeAndValidateParametersToTemp(Bundle extras) {

		IllegalArgumentException invalidPort = new IllegalArgumentException(
		        "The "
		                + EXTRA_PORT
		                + " is invalid, it must be a positive integer representing the port that the socket server is on. Ex. 3013");

		IllegalArgumentException missingUser = new IllegalArgumentException("The "
		        + EXTRA_CURRENT_USER + " must be supplied to this service before starting it");

		// user
		currentUser = (User) extras.getSerializable(EXTRA_CURRENT_USER);
		if (currentUser == null) {
			throw missingUser;
		}

		// port
		socketServerPort = extras.getInt(EXTRA_PORT, -1);
		if (socketServerPort <= 0) {
			throw invalidPort;
		}

	}

	// }}

	// ===============================================================================
	// {{ Real Time Events Manager Implementation Methods

	@Override
	public void onConnected() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onRegistered() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onDisconnected() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onUserLoggedIn(UserStub user) {
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_USER_LOGGED_IN);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);

		broadcastIntent.putExtra(EXTRA_LOGGED_IN_USER, user);

		sendBroadcast(broadcastIntent);
		FLLogger.d(TAG, "Broadcasted: " + ACTION_ON_USER_LOGGED_IN);
	}

	@Override
	public void onUserLoggedOut(UserStub user) {
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(ACTION_ON_USER_LOGGED_OUT);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);

		broadcastIntent.putExtra(EXTRA_LOGGED_OUT_USER, user);

		sendBroadcast(broadcastIntent);

	}

	// }}

}
